package edu.protbioinfo;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import edu.protbioinfo.Utils.Pair;

public class QueryMatcher {
	LabeledMatrix<Double> substitutionMatrix = ProteinSubstitutionMatrices.blosum62;
	
	int wordLength = 1;
	double threshold = 0.;
	char[] alphabets = null;
	
	public QueryMatcher(char[] alphabets, int wordLength, double threshold) {
		
		if(ArrayUtils.isEmpty(alphabets)){
			throw new IllegalArgumentException("Alphabets should be not empty");
		}
		
		this.alphabets = alphabets;
		this.wordLength = wordLength;
		this.threshold = threshold;
	}

	public List<MatchWord> generate(String query){
		
		List<MatchWord> matches = new ArrayList<MatchWord>();
		
		int length = query.length();	
		if(!StringUtils.isEmpty(query) && length >= wordLength){
			List<String> words = getWords();
			for(String word : words){
				for(int i = 0; i < length; i++){
					
					int end = i + wordLength;
					if(end >= length){
						break;
					}
					
					String token = StringUtils.substring(query, i, end);
					double score = evalCost(token, word);
					
					if(Double.compare(score, threshold) >= 0){
						matches.add(new MatchWord(new Pair<String, String>(token, word), i, score));
					}
				}
			}
		}
		
		return matches;
	}
	
	private double evalCost(String target, String source) {
		if(StringUtils.isEmpty(target) || StringUtils.isEmpty(source)){
			throw new IllegalArgumentException("Empty target or source");
		}
		
		if(target.length() != source.length()){
			throw new IllegalArgumentException("Different length");
		}
		
		double score = 0.;
		
		for(int i = 0; i < target.length(); i++){
			score += substitutionMatrix.getValue(target.charAt(i), source.charAt(i));
		}
		return score;
	}

	private List<String> getWords() {
//		String word = "";
//		for(int i = 0; i < wordLength; i++){
//			for(int j = 0; j < alphabets.length; j++){
//					word += alphabets[j];
//				
//			}
//		}
//		return null;
		List<String> words = new ArrayList<String>();
		words.add("AA");
		words.add("AI");
		words.add("AL");
		words.add("AS");
		words.add("IA");
		words.add("II");
		words.add("IL");
		words.add("IS");
		words.add("LA");
		words.add("LI");
		words.add("LL");
		words.add("LS");
		words.add("SA");
		words.add("SI");
		words.add("SL");
		words.add("SS");
		return words;
	}

	public char[] getAlphabets() {
		return alphabets;
	}


	public void setAlphabets(char[] alphabets) {
		this.alphabets = alphabets;
	}


	public LabeledMatrix<Double> getSubstitutionMatrix() {
		return substitutionMatrix;
	}

	public void setSubstitutionMatrix(LabeledMatrix<Double> substitutionMatrix) {
		this.substitutionMatrix = substitutionMatrix;
	}

	public int getWordLength() {
		return wordLength;
	}

	public void setWordLength(int wordLength) {
		this.wordLength = wordLength;
	}


	public double getThreshold() {
		return threshold;
	}


	public void setThreshold(double threshold) {
		this.threshold = threshold;
	}


	class MatchWord{
		private Pair<String, String> wordPair;
		private int index;
		private double score;
		
		public MatchWord(Pair<String, String> wordPair, int index, double score) {
			this.wordPair = wordPair;
			this.index = index;
			this.score = score;
		}

		public Pair<String, String> getWordPair() {
			return wordPair;
		}

		public int getIndex() {
			return index;
		}

		public double getScore() {
			return score;
		}

		public String toPrettyString(){
			StringBuffer sb = new StringBuffer();
			sb.append(wordPair.second() +"(" + index + ":" + score + ")");
			
			return sb.toString();
		}
	}
}
